package com.feidee.data.report.dao.impl;

import com.alibaba.fastjson.JSONObject;
import com.feidee.data.report.constant.Constant;
import com.feidee.data.report.dao.IRedisDao;
import com.feidee.data.report.dao.IRealTimeReportDao;
import com.feidee.data.report.exception.DataDaoException;
import com.feidee.data.report.model.RealTimeReportConfigModel.ViewSqlModel;
import com.feidee.data.report.util.DbOperationUtil;
import com.feidee.data.report.util.JdbcManager;
import com.feidee.data.report.util.ToolUtils;
import com.feidee.fdcommon.configuration.CustomConfiguration;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonParser;
import org.apache.log4j.Logger;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class RealTimeReportDaoImpl implements IRealTimeReportDao {

    public Logger logger = Logger.getLogger(RealTimeReportDaoImpl.class);

//    private DataSource snappyDataSourceDefault;
//    private DataSource snappyDataSource_36;

    @Resource
    private DataSource confDataSource;

    @Override
    public Map<Map<String, JSONObject>, Map<String, JSONObject>> runSql(IRedisDao redisDao, String dimStr, String sql) {
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        Map<Map<String, JSONObject>, Map<String, JSONObject>> resultMap = new HashMap<>();
        try {
            String[] split = dimStr.split("#", -1);
            String redisKey = split[0];
            String[] redisKeySplit = redisKey.split("&", -1);
            String view_name = redisKeySplit[0];
            String end_date = redisKeySplit[3];
            String engine = dimStr.split("€", -1)[1];

            if ("impala".equals(engine)) {
                connection = JdbcManager.getConnection(
                        Constant.IMPALA_DRIVER, Constant.IMPALA_CONNECTION, Constant.IMPALA_USER, Constant.IMPALA_PWD
                );
                logger.info("实时报表查询视图: " + view_name + " 连接Impala默认环境！");
            } /*else {
                if (Constant.SNAPPYDATA_RUN_ON_36.contains(view_name)) {
                    connection = snappyDataSource_36.getConnection();
                    logger.info("实时报表查询视图: " + view_name + " 指定连接SnappyData36环境！");
                } else {
                    connection = snappyDataSourceDefault.getConnection();
                    logger.info("实时报表查询视图: " + view_name + " 连接SnappyData默认环境！");
                }
            }*/ else if ("spark".equals(engine)) {
                connection = JdbcManager.getConnection(Constant.HIVE_DRIVER, Constant.SPARK_SQL_CONNECTION,
                        Constant.REALREPORT_USER, Constant.REALREPORT_PWD);
                logger.info("实时报表查询视图: " + view_name + " 连接Spark环境！");
            } else if ("spark-kudu".equals(engine)) {
                connection = JdbcManager.getConnection(Constant.HIVE_DRIVER, Constant.SPARK_KUDU_CONNECTION,
                        Constant.REALREPORT_USER, Constant.REALREPORT_PWD);
                logger.info("实时报表查询视图: " + view_name + " 连接Spark-kudu环境！");
            } else if("impala(随云)".equals(engine)){
                Class.forName(Constant.IMPALA_DRIVER);
                connection = DriverManager.getConnection(Constant.IMPALA_CONNECTION);
               /* connection = JdbcManager.getConnection(Constant.IMPALA_DRIVER, Constant.IMPALA_SUIYUN_CONNECTION,
                        Constant.IMPALA_SUIYUN_USER, Constant.IMPALA_SUIYUN_PWD);*/
                logger.info("实时报表查询视图: " + view_name + " 连接impala(随云)环境！");
            }
            /*else {
                if (Constant.SNAPPYDATA_RUN_ON_36.contains(view_name)) {
                    connection = snappyDataSource_36.getConnection();
                    logger.info("实时报表查询视图: " + view_name + " 指定连接SnappyData36环境！");
                } else {
                    connection = snappyDataSourceDefault.getConnection();
                    logger.info("实时报表查询视图: " + view_name + " 连接SnappyData默认环境！");
                }
            }*/

            statement = connection.createStatement();
            resultSet = statement.executeQuery(sql);

            List<String> dims = new ArrayList<>();
            if (ToolUtils.isNotNull(redisKeySplit[1])) {
                // 转换为大写方便与snappyData元数据比较
                dims = Arrays.asList(redisKeySplit[1].toUpperCase().split(",", -1));
            }
            ResultSetMetaData metaData = resultSet.getMetaData();
            int columnCount = metaData.getColumnCount();
            String[] colN = new String[columnCount];
            for (int i = 0; i < columnCount; i++) {
                colN[i] = metaData.getColumnName(i + 1);
            }
            while (resultSet.next()) {
                // 存储维度值
                JSONObject dimJsonObject = new JSONObject();
                // 存储所有指标值，即使指标没被选中
                JSONObject metricJsonObject = new JSONObject();
                for (int i = 0; i < colN.length; i++) {
                    String val = resultSet.getString(i + 1);
                    if (dims.contains(colN[i].toUpperCase())) {
                        dimJsonObject.put(colN[i].toUpperCase(), val);
                    } else {
                        metricJsonObject.put(colN[i].toUpperCase(), val);
                    }
                }
                Map<String, JSONObject> keyMap = new HashMap<>();
                Map<String, JSONObject> valueMap = new HashMap<>();
                keyMap.put("dims", dimJsonObject);
                valueMap.put(view_name, metricJsonObject);
                resultMap.put(keyMap, valueMap);
            }
            // 如果查询日期在当天之前则不过期缓存进redis，否则过期缓存进redis
            if (end_date.compareTo(ToolUtils.getCurrentDay()) < 0) {
                redisDao.insertMapWithLife(redisKey, resultMap, CustomConfiguration.getInt("realTime.redis.time" +
                        ".noexpire", 180));
            } else {
                redisDao.insertMapWithLife(redisKey, resultMap, CustomConfiguration.getInt("realTime.redis.time" +
                        ".expire", 180));
            }
        } catch (Exception e) {
            logger.error("实时报表查询SQL: " + sql + " 获取结果异常", e);
            return null;
        } finally {
            try {
                JdbcManager.destroy(connection, statement, resultSet);
            } catch (DataDaoException e) {
                logger.error("关闭连接失败");
            }
        }
        String resultMapStr = resultMap.toString();
        resultMapStr = resultMapStr.substring(0, resultMapStr.length() > 1000 ? 1000 : resultMapStr.length());
        logger.info("实时报表key为: " + dimStr + " 查询的结果为: " + resultMapStr);
        return resultMap;
    }

    @Override
    public String getConfMeta() {
        Connection conn = null;
        Statement statement = null;
        ResultSet rs = null;
        Gson gson = new Gson();
        JsonParser jsonParser = new JsonParser();
        List<String> metas = new ArrayList<>();
        String sql = "select * from olap_conf_meta";
        try {
            conn = confDataSource.getConnection();
            if (!conn.isClosed()) {
                logger.info("mysql连接成功!");
            } else {
                logger.info("mysql连接失败!");
            }
            statement = conn.createStatement();
            rs = statement.executeQuery(sql);
            while (rs.next()) {
                Map<String, Object> meta = new HashMap<>();
                String businessENName = rs.getString("business_en_name");
                String businessCNName = rs.getString("business_cn_name");
                String dimConfig = rs.getString("dim_config");
                String viewConfig = rs.getString("view_config");
                JsonArray dimArr = jsonParser.parse(dimConfig).getAsJsonArray();
                JsonArray viewArr = jsonParser.parse(viewConfig).getAsJsonArray();
                meta.put("business_en_name", businessENName);
                meta.put("business_cn_name", businessCNName);
                meta.put("dim_config", dimArr);
                meta.put("view_config", viewArr);
                String json = gson.toJson(meta);
                metas.add(json);
            }
        } catch (Exception e) {
            logger.error("Mysql conf_meta 获取异常!", e);
        } finally {
            DbOperationUtil.cleanConnEnv(conn, statement, rs);
        }
        return metas.toString();
    }

    @Override
    public Map<String, String> getView(String viewName) {
        Connection conn = null;
        PreparedStatement preStatement = null;
        ResultSet rs = null;
        Map<String, String> viewInfo = new HashMap<>(16);
        try {
            conn = confDataSource.getConnection();
            String sql = "select * from olap_conf_view where view_name = ?";
            preStatement = conn.prepareStatement(sql);
            preStatement.setString(1, viewName);
            rs = preStatement.executeQuery();
            while (rs.next()) {
                viewInfo.put("sql", rs.getString("view_define"));
                viewInfo.put("engine", rs.getString("engine"));
            }
        } catch (Exception e) {
            logger.error("Mysql conf_view 获取异常!", e);
        } finally {
            DbOperationUtil.cleanConnEnv(conn, preStatement, rs);
        }
        return viewInfo;
    }

    @Override
    public String setConfMeta(String businessCnName, String businessEnName, String dimConfig, String viewConfig) {
        Connection conn = null;
        PreparedStatement preStatement = null;
        String code = "0";
        try {
            conn = confDataSource.getConnection();
            String sql = "insert into olap_conf_meta(business_en_name,business_cn_name,dim_config,view_config) " +
                    "VALUES(?,?,?,?) on duplicate key update `business_en_name`=?,`business_cn_name`=?," +
                    "`dim_config`=?,`view_config`=?";
            preStatement = conn.prepareStatement(sql);
            preStatement.setString(1, businessEnName);
            preStatement.setString(2, businessCnName);
            preStatement.setString(3, dimConfig);
            preStatement.setString(4, viewConfig);
            preStatement.setString(5, businessEnName);
            preStatement.setString(6, businessCnName);
            preStatement.setString(7, dimConfig);
            preStatement.setString(8, viewConfig);
            preStatement.execute();
        } catch (Exception e) {
            code = "-1";
            logger.error("实时报表更新元数据表异常!", e);
        } finally {
            DbOperationUtil.cleanConnEnv(conn, preStatement);
        }
        return code;
    }

    @Override
    public String setConfView(String businessEnName, List<ViewSqlModel> viewSqlModels) {
        Connection conn = null;
        PreparedStatement preStatement = null;
        String code = "0";
        try {
            conn = confDataSource.getConnection();
            String sql = "insert into olap_conf_view(view_name,view_define,engine) VALUES(?,?,?) on duplicate key " +
                    "update `view_name`=?,`view_define`=?,`engine`=?";
            preStatement = conn.prepareStatement(sql);
            for (ViewSqlModel viewSqlModel : viewSqlModels) {
                String viewName = viewSqlModel.getView_name();
                String viewDefine = viewSqlModel.getView_define();
                String engine = viewSqlModel.getEngine();
                preStatement.setString(1, viewName);
                preStatement.setString(2, viewDefine);
                preStatement.setString(3, engine);
                preStatement.setString(4, viewName);
                preStatement.setString(5, viewDefine);
                preStatement.setString(6, engine);
                preStatement.addBatch();
            }
            preStatement.executeBatch();
        } catch (Exception e) {
            code = "-1";
            logger.error("实时报表更新视图SQL数据表异常!", e);
        } finally {
            DbOperationUtil.cleanConnEnv(conn, preStatement);
        }
        return code;
    }

//    public void setSnappyDataSourceDefault(DataSource snappyDataSourceDefault) {
//        this.snappyDataSourceDefault = snappyDataSourceDefault;
//    }
//
//    public void setSnappyDataSource_36(DataSource snappyDataSource_36) {
//        this.snappyDataSource_36 = snappyDataSource_36;
//    }
}
